#include "Flock.h"
#include "Timer.h"
#include "Agent.h"
#include "AgentGroup.h"

namespace Engine
{
	Flock::Flock():m_timeBetweenGroupChecks(0.0f), m_timeToNextCheck(0.0f)
	{
		m_behaviours.push_back(WeightedSteeringBehaviour(&m_cohesion, .66f));

		m_behaviours.push_back(WeightedSteeringBehaviour(&m_separation, .66f));

		m_behaviours.push_back(WeightedSteeringBehaviour(&m_velocityMatch, .33f));

		m_velocityMatch.SetTarget(&m_velMatchTarget);
	}

	void Flock::Update(SteeringOutput* output)
	{
		m_timeToNextCheck -= TheTimer::Instance() ->GetDT();
		if(m_timeToNextCheck <= 0.0f)
		{
			m_timeToNextCheck = m_timeBetweenGroupChecks;

			Vec3 avgVel;
			AgentGroup* g = m_parent ->GetGroup();
			for(auto it = g ->GetNeighbours().begin(); it != g ->GetNeighbours().end(); ++it)
				avgVel += it ->second ->GetVel();

			avgVel /= (float)g ->GetNeighbours().size();
			
			m_velMatchTarget.SetVel(avgVel);
		}

		BlendedSteering::Update(output);
	}

	void Flock::SetParent(Agent* parent)
	{
		m_velocityMatch.SetParent(parent);
		SteeringBehaviour::SetParent(parent);
	}

	void Flock::SetValues(float separationThreshold, 
				          float separationDecayCoefficient, 
				          float cohesionThreshold, 
				          float cohesionDecayCoefficient,
				          float velMatchTimeToTarget, 
						  float timeBetweenGroupChecks)
	{
		SetSeparationValues(separationThreshold, separationDecayCoefficient);
		SetCohesionValues(cohesionThreshold, cohesionDecayCoefficient);
		SetVelocityMatchTimeToTarget(velMatchTimeToTarget);

		m_timeBetweenGroupChecks = timeBetweenGroupChecks;
	}
	
	void Flock::SetSeparationValues(float threshold, float decayCoefficient)
	{
		m_separation.SetThreshold(threshold);
		m_separation.SetDecayCoefficient(decayCoefficient);
	}
	
	void Flock::SetCohesionValues(float threshold, float decayCoefficient)
	{
		m_cohesion.SetThreshold(threshold);
		m_cohesion.SetDecayCoefficient(decayCoefficient);
	}

	void Flock::SetVelocityMatchTimeToTarget(float t)
	{
		m_velocityMatch.SetTimeToTarget(t);
	}

	//getters
	float Flock::GetSeparationThreshold() const
	{
		return m_separation.GetThreshold();
	}
	
	float Flock::GetSeparationDecayCoefficient() const
	{
		return m_separation.GetDecayCoefficient();
	}

	float Flock::GetCohesionThreshold() const
	{
		return m_cohesion.GetThreshold();
	}

	float Flock::GetCohesionDecayCoefficient() const
	{
		return m_cohesion.GetDecayCoefficient();
	}

	float Flock::GetVelMatchTimeToTarget() const
	{
		return m_velocityMatch.GetTimeToTarget();
	}
}